package cn.edu.hnu.gpg.service;

import cn.edu.hnu.gpg.dao.MessageMapper;
import cn.edu.hnu.gpg.dto.MessageWithName;
import cn.edu.hnu.gpg.dto.UniversalUser;
import cn.edu.hnu.gpg.entity.Message;
import cn.edu.hnu.gpg.entity.MessageExample;
import cn.edu.hnu.gpg.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Service
public class MessageServiceImpl implements MessageService {

    private MessageMapper messageMapper;

    @Autowired
    private UserService userService;

    @Autowired
    public MessageServiceImpl(MessageMapper messageMapper){
        this.messageMapper = messageMapper;
    }

    @Override
    public boolean sendMessage(int from_user_id, String to_username, String content) {
        if (from_user_id <1 || to_username.isEmpty())
            return false;

        int to_user_id = userService.findUserByUsername(to_username).getUserId();

        Message message = new Message();
        message.setStatus("0");
        message.setContent(content);
        message.setFromUserId(from_user_id);
        message.setToUserId(to_user_id);
        return messageMapper.insertSelective(message) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<Integer> sendMessage(Integer sender, List<Integer> receiverList, String messageContent) {

        if (sender == null || receiverList == null || messageContent == null)
            throw new IllegalArgumentException("Argument must not be null");

        List<Integer> messageIdList = new ArrayList<>(receiverList.size());

        for (Integer receiverId : receiverList) {
            Message messageTemplate = new Message();
            messageTemplate.setFromUserId(sender);
            messageTemplate.setContent(messageContent);
            messageTemplate.setToUserId(receiverId);

            messageMapper.insertSelective(messageTemplate);

            if (messageTemplate.getMessageId() != null)
                messageIdList.add(messageTemplate.getMessageId());
        }

        return messageIdList;
    }

    @Override
    public Message findMessageById(Integer messageId) {
        return messageMapper.selectByPrimaryKey(messageId);
    }

    @Override
    public MessageWithName message2MessageWithName(Message messages) {
        throw new RuntimeException("Not implemented");
    }

    @Override
    public List<MessageWithName> message2MessageWithName(List<Message> messages) {
        if (messages == null)
            return null;

        List<MessageWithName> withNameList = new ArrayList<>(messages.size());
        Map<Integer, String> usernameMap = new HashMap<>(messages.size() / 2);
        for (Message message :
                messages) {
            MessageWithName messageWithName = new MessageWithName(message);
            messageWithName.setFromUserName(userId2Username(message.getFromUserId(), usernameMap));
            messageWithName.setToUserName(userId2Username(message.getToUserId(), usernameMap));
            withNameList.add(messageWithName);
        }
        return withNameList;
    }

    private String userId2Username(Integer userId, Map<Integer, String> cache) {
        if (cache == null)
            throw new IllegalArgumentException("Map<Integer, String> must not be null");

        String username = cache.get(userId);

        if (username == null) {
            UniversalUser user = userService.getUniversalUserByUserId(userId);
            cache.put(userId, user.getName());
            username = user.getName();
        }

        return username;
    }

    @Override
    public List<Message> readAllReceiveMessage(int to_user_id) {
        if (to_user_id < 1)
            return null;

        MessageExample messageExample = new MessageExample();
        messageExample.or().andToUserIdEqualTo(to_user_id);
        List<Message> messages = messageMapper.selectByExampleWithBLOBs(messageExample);
        return messages.size()>0 ? messages : null;
    }

    @Override
    public List<Message> readAllSendMessage(int from_user_id) {
        if (from_user_id <1)
            return null;

        MessageExample messageExample = new MessageExample();
        messageExample.or().andFromUserIdEqualTo(from_user_id);
        List<Message> messages = messageMapper.selectByExampleWithBLOBs(messageExample);
        return messages.size() > 0 ? messages : null ;
    }

    @Override
    public List<Message> findNewMessage(int to_user_id) {
        if (to_user_id <1)
            return null;

        MessageExample messageExample = new MessageExample();
        messageExample.or().andStatusEqualTo("0");
        List<Message> messages = messageMapper.selectByExampleWithBLOBs(messageExample);
        return messages.size()>0 ? messages : null;
    }

    @Override
    public boolean markMessageReaded(int message_id) {
        if (message_id < 1)
            return false;

        Message message = messageMapper.selectByPrimaryKey(message_id);
        message.setStatus("1");
        return messageMapper.updateByPrimaryKeySelective(message) > 0;
    }

    @Override
    public boolean markMessageReaded(int from_user_id, int to_user_id, Date date) {
        if (from_user_id < 1 || to_user_id < 1)
            return false;

        MessageExample messageExample = new MessageExample();
        messageExample.or().andFromUserIdEqualTo(from_user_id).andToUserIdEqualTo(to_user_id).andSendTimeEqualTo(date);
        Message message = messageMapper.selectByExampleWithBLOBs(messageExample).get(0);
        message.setStatus("1");
        return messageMapper.updateByPrimaryKeySelective(message) > 0;
    }

    @Override
    public boolean markMessageReaded(String from_username, int to_user_id, Date date) {
        if (from_username.isEmpty() || to_user_id < 1)
            return false;

        int from_user_id = userService.findUserByUsername(from_username).getUserId();
        MessageExample messageExample = new MessageExample();
        messageExample.or().andFromUserIdEqualTo(from_user_id).andToUserIdEqualTo(to_user_id).andSendTimeEqualTo(date);
        Message message = messageMapper.selectByExampleWithBLOBs(messageExample).get(0);
        message.setStatus("1");
        return messageMapper.updateByPrimaryKeySelective(message) > 0;
    }

    @Override
    public boolean deleteByPk(int message_id) {
        if (message_id < 1)
            return false;

        return  messageMapper.deleteByPrimaryKey(message_id) > 0 ;
    }
}
